package android.slc.box.core.utils;

import android.slc.box.rx.SlcRxJavaUtils;
import android.slc.box.rxjavafx.schedulers.JavaFxScheduler;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.log.Log;
import io.reactivex.rxjava3.annotations.NonNull;
import io.reactivex.rxjava3.core.Observable;
import io.reactivex.rxjava3.core.ObservableEmitter;
import io.reactivex.rxjava3.core.ObservableOnSubscribe;
import io.reactivex.rxjava3.functions.Function;
import io.reactivex.rxjava3.schedulers.Schedulers;
import org.apache.commons.collections4.IterableUtils;
import org.jetbrains.annotations.NotNull;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @author slc
 * @date 2022/09/17 下午 5:36
 */
public class BoxTaskManager {
    private static final ConcurrentHashMap<String, List<BoxTask>> taskListByGroup = new ConcurrentHashMap<>();

    public static void addTask(BoxTask boxTask) {
        if (!taskListByGroup.containsKey(boxTask.getGroupName())) {
            taskListByGroup.put(boxTask.getGroupName(), new ArrayList<>());
        }
        List<BoxTask> boxTaskList = taskListByGroup.get(boxTask.groupName);
        boxTaskList.add(boxTask);
    }

    public static Observable<String> runTask(String groupName) {
        List<BoxTask> boxTaskList = taskListByGroup.get(groupName);
        if (CollUtil.isEmpty(boxTaskList)) {
            return Observable.create(new ObservableOnSubscribe<String>() {
                @Override
                public void subscribe(@NotNull ObservableEmitter<String> emitter) {
                    emitter.onNext("");
                    emitter.onComplete();
                }
            });
        }
        Observable<?>[] taskObservableArray = new Observable[boxTaskList.size()];
        List<Observable<String>> taskObservableList = new ArrayList<>();
        IterableUtils.forEach(boxTaskList, input -> {
            Observable<String> taskObservable = Observable.just(input).map(new Function<BoxTask, String>() {
                @Override
                public String apply(@NotNull BoxTask boxTask) {
                    try {
                        boxTask.run(boxTask.id);
                    } catch (Throwable e) {
                        Log.get().error("BoxTask：{}", e);
                    }
                    return boxTask.id;
                }
            });
            if (input.isAsyncTask) {
                taskObservable = taskObservable.subscribeOn(Schedulers.io());
            } else {
                taskObservable = taskObservable.subscribeOn(JavaFxScheduler.platform());
            }
            taskObservableList.add(taskObservable);
        });
        taskObservableList.toArray(taskObservableArray);
        return Observable.concatArray(taskObservableArray).map(o -> (String) o).compose(SlcRxJavaUtils.applyOoAndroidSchedulers());
    }

    public static abstract class BoxTask {
        public final String id;
        public final String groupName;
        public final boolean isAsyncTask;

        public BoxTask(@NonNull String id, @NonNull String groupName) {
            this(id, groupName, false);
        }

        public BoxTask(@NonNull String id, @NonNull String groupName, boolean isAsyncTask) {
            this.id = id;
            this.groupName = groupName;
            this.isAsyncTask = isAsyncTask;
        }

        public String getId() {
            return id;
        }

        public String getGroupName() {
            return groupName;
        }

        public boolean isAsyncTask() {
            return isAsyncTask;
        }

        public abstract void run(String name);
    }
}
